package com.mrx.bot.telegram.utils;

import com.alibaba.fastjson2.JSON;
import com.mrx.bot.telegram.model.BotConfig;
import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.InputStream;
import java.net.Proxy;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Mr.X
 * @since 2025/6/13 21:10
 */
public class BotConfigLoader {

    private static volatile BotConfig botConfig;

    private static final String ENV_PREFIX = "BOT_CONFIG_";

    private static final Set<Pair<String, BiConsumer<BotConfig, String>>> ENV_KEYS = Set.of(
            Pair.of("TOKEN", wrapSetter(BotConfig::setToken, String.class)),
            Pair.of("BOT_USERNAME", wrapSetter(BotConfig::setBotUsername, String.class)),
            Pair.of("CREATOR_ID", wrapSetter(BotConfig::setCreatorId, Long.class)),
            Pair.of("DATA_PATH", wrapSetter(BotConfig::setDataPath, String.class)),
            Pair.of("PROXY_TYPE", wrapSetter(BotConfig::setProxyType, Proxy.Type.class)),
            Pair.of("PROXY_HOST", wrapSetter(BotConfig::setProxyHost, String.class)),
            Pair.of("PROXY_PORT", wrapSetter(BotConfig::setProxyPort, Integer.class))
    );

    private static final Logger logger = LoggerFactory.getLogger(BotConfigLoader.class);

    @SneakyThrows
    public static BotConfig getBotConfig() {
        if (botConfig == null) {
            synchronized (BotConfigLoader.class) {
                if (botConfig == null) {
                    botConfig = loadConfigFromEnv().orElseGet(BotConfigLoader::loadConfig);
                    logger.info("加载 botConfig: {}", JSON.toJSONString(botConfig));
                    if (missRequiredParam(botConfig)) {
                        throw new IllegalArgumentException("bot 参数校验失败, 请检查是否缺少必填参数");
                    }
                    String dataPath = botConfig.getDataPath();
                    if (dataPath != null && !dataPath.isBlank()) {
                        FileUtils.forceMkdir(new File(dataPath));
                    }
                }
            }
        }
        return botConfig;
    }

    private static Optional<BotConfig> loadConfigFromEnv() {
        logger.info("尝试从环境变量加载配置");
        Map<String, String> env = System.getenv();
        Map<String, BiConsumer<BotConfig, String>> keySetterMap = ENV_KEYS.stream()
                .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
        Map<String, String> envKeyMap = ENV_KEYS.stream().collect(Collectors.toMap(
                Pair::getKey, it -> env.getOrDefault(ENV_PREFIX + it.getKey(), "")
        ));
        BotConfig config = new BotConfig();
        for (Map.Entry<String, String> entry : envKeyMap.entrySet()) {
            BiConsumer<BotConfig, String> setter = keySetterMap.get(entry.getKey());
            setter.accept(config, entry.getValue());
        }
        logger.info("环境变量配置加载结果: {}", JSON.toJSONString(config));
        if (missRequiredParam(config)) {
            return Optional.empty();
        }
        return Optional.of(config);
    }

    private static BotConfig loadConfig() {
        logger.info("从配置文件加载配置");
        InputStream resource = BotConfigLoader.class.getClassLoader().getResourceAsStream("bot.yml");
        return new Yaml().loadAs(resource, BotConfig.class);
    }

    @SuppressWarnings("unchecked")
    private static <T> BiConsumer<BotConfig, String> wrapSetter(BiConsumer<BotConfig, T> origin, Class<T> paramType) {
        return (config, value) -> {
            // 处理几种空值
            if (value.isBlank() || "null".equals(value) || "0".equals(value)) {
                origin.accept(config, null);
                return;
            }
            switch (paramType) {
                case Class<?> clazz when String.class.isAssignableFrom(clazz) -> origin.accept(config, (T) value);
                case Class<?> clazz when Long.class.isAssignableFrom(clazz) ->
                        origin.accept(config, (T) Long.valueOf(value));
                case Class<?> clazz when Proxy.Type.class.isAssignableFrom(clazz) ->
                        origin.accept(config, (T) Proxy.Type.valueOf(value.toUpperCase()));
                case Class<?> clazz when Integer.class.isAssignableFrom(clazz) ->
                        origin.accept(config, (T) Integer.valueOf(value));
                case null, default -> throw new IllegalStateException("不支持的类型");
            }
        };
    }

    private static boolean missRequiredParam(BotConfig config) {
        // 三个必填参数
        return Stream.of(config.getToken(), config.getBotUsername(), config.getCreatorId()).anyMatch(it ->
                switch (it) {
                    case String s -> s.isBlank();
                    case Number s -> s.intValue() == 0;
                    case null -> true;
                    default -> false;
                }
        );
    }

}
